package com.ctshk.rpc.payment.utils.alipay;

import cn.hutool.core.codec.Base64Decoder;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @BelongsProject: ctshk-cloud
 * @BelongsPackage: com.ctshk.rpc.payment.utils.alipay
 * @Author: hef
 * @CreateTime: 2021-04-20 17:55
 * @Description: 描述
 */
public class AliPayUtil {
    private static final String SIGN_RSA = "SHA1WithRSA";
    private static final String SIGN_RSA2 = "SHA256WithRSA";
    /**
     * 生成预签名字符串
     *
     * @param parameters
     * @return
     */
    public static String generatePreSignString(Map<String, String> parameters) {
        Map<String, String> _parameters = new HashMap<>(parameters);
        //1.0
        _parameters.remove("sign_type");
        //1.0
        _parameters.remove("sign");
        return _parameters.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).map(a1 -> a1.getKey() + "=" + a1.getValue()).collect(Collectors.joining("&"));
    }


    /**
     * RSA
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     */
    public static String RSA(String content, String privateKey, String charset) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(priPKCS8);
            Signature signature = Signature.getInstance("SHA1WithRSA");
            signature.initSign(priKey);
            signature.update(content.getBytes(charset));
            byte[] signed = signature.sign();
            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            throw new RuntimeException("the key's format maybe not right");
        }
    }

    /**
     * RSA2
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     */
    public static String RSA2(String content, String privateKey, String charset) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(priPKCS8);
            Signature signature = Signature.getInstance(SIGN_RSA2);
            signature.initSign(priKey);
            signature.update(content.getBytes(charset));
            byte[] signed = signature.sign();
            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            throw new RuntimeException("the key's format maybe not right");
        }
    }

    /**
     * RSA验签名检查 RSA sign verification
     *
     * @param content        待签名数据 pre-sign string
     * @param sign           签名值 sign
     * @param ali_public_key 支付宝公钥 Alipay's public key
     * @param input_charset  编码格式 charset
     * @return 布尔值 boolean
     */
    public static boolean rsaVerify(String content, String sign, String ali_public_key, String input_charset) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64Decoder.decode(ali_public_key);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature
                    .getInstance("SHA1WithRSA");
            signature.initVerify(pubKey);
            signature.update(content.getBytes(input_charset));
            boolean bverify = signature.verify(Base64Decoder.decode(sign));
            return bverify;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * MD5
     *
     * @param content
     * @param key
     * @param charset
     * @return
     */
    public static String MD5(String content, String key, String charset) {
        try {
            content = content + key;
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(content.getBytes(charset));
            byte[] digest = md5.digest();
            return IntStream.range(0, digest.length).map(a1 -> digest[a1]).mapToObj(a1 -> {
                String hexString = Integer.toHexString(0xff & a1);
                return (hexString.length() < 2) ? ("0" + hexString) : hexString;
            }).collect(Collectors.joining());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("sign error");
        }
    }


}
